# Лямбда-типы

Лямбда-тип позволяет выразить тип более высокого типа напрямую, без определения.

```dotty
[X, Y] =>> Map[Y, X]
```

Например, приведенный выше тип определяет конструктор бинарного вида, 
который сопоставляет аргументы `X` и `Y` с `Map[Y, X]`. 
Параметры типа лямбда-выражений могут иметь границы, но они не могут содержать аннотации вариантности `+` или `-`.

Пример:

```dotty
type XY = [X, Y] =>> Map[Y, X]
val numbers: XY[String, Int] = Map(1 -> "first", 2 -> "second")
// numbers: Map[Int, String] = Map(1 -> "first", 2 -> "second")
numbers(1)
// res0: String = "first"
```

#### Проверка типа

Лямбда-тип, например, `[X] =>> F[X]` определяет функцию от типов к типам. 
Параметры могут иметь ограничения. 
Если параметр ограничен, как `[X >: L <: U] =>> F[X]`, 
то проверяется, что аргументы параметров соответствуют границам `L` и `U`. 
Только верхняя граница `U` рассматривается включительно, т.е. что `X` может в неё входить.

#### Правила подтипа

Рассмотрим два лямбда-выражения

```dotty
type TL1  =  [X >: L1 <: U1] =>> R1
type TL2  =  [X >: L2 <: U2] =>> R2
```

Тогда `TL1 <: TL2`, если
- интервал типов `L2 .. U2` содержится в интервале типа `L1 .. U1` (т.е. `L1 <: L2` и `U2 <: U1`),
- `R1 <: R2`

Предполагается, что частично применяемый конструктор типа `List` 
эквивалентен его [Eta Expansion](../functions/eta.md). 
Т.е. `List = [X] =>> List[X]`.
Это позволяет сравнивать конструкторы типов с лямбда-выражениями типов.

#### Связь с определениями параметризованного типа

Определение параметризованного типа

```dotty
type T[X] = R
```

рассматривается как сокращение для непараметризованного определения с лямбда-типом в правой части:

```dotty
type T = [X] =>> R
```

Если определение типа содержит аннотации вариантности `+` или `-`, 
проверяется, удовлетворяет ли лямбда аннотации вариантности. 
Например,

```dotty
type F2[A, +B] = A => B
```

расширяется до

```dotty
type F2 = [A, B] =>> A => B
```

и при этом проверяется, что параметр `B` появляется ковариантно в `A => B`.

Параметризованный абстрактный тип

```dotty
type T[X] >: L <: U
```

считается сокращением для непараметризованного абстрактного типа с лямбда-выражениями типа в качестве границ.

```dotty
type T >: ([X] =>> L) <: ([X] =>> U)
```

Однако, если `L` - `Nothing`, то он не параметризован, т.к. `Nothing` считается нижним типом для всех видов. 
Например,

```dotty
type T[X] <: X => X
```

расширяется до

```dotty
type T >: Nothing <: ([X] =>> X => X)
```

вместо

```dotty
type T >: ([X] =>> Nothing) <: ([X] =>> X => X)
```

Те же расширения применяются к параметрам типа. 
Например,

```dotty
[F[X] <: Coll[X]]
```

рассматривается как сокращение для

```dotty
[F >: Nothing <: [X] =>> Coll[X]]
```

Абстрактные типы и псевдонимы непрозрачных типов запоминают вариантность, с которыми были созданы. 
Итак, тип

```dotty
type F2[-A, +B]
```

известно, что он контравариантен в `A` и ковариантен в `B` 
и может быть реализован только с типами, которые удовлетворяют этим ограничениям. 
Так же

```dotty
opaque type O[X] = List[X]
```

`O` известно, что оно инвариантно (а не ковариантно, как следует из его правой части). 
С другой стороны, прозрачный псевдоним

```dotty
type O2[X] = List[X]
```

будет рассматриваться как ковариантный, `X` используется ковариантно в его правой части.

#### Каррированные параметры типа

Тело лямбда-типа может снова быть лямбда-типом. Пример:

```dotty
type TL = [X] =>> [Y] =>> (X, Y)
```


---

**Ссылки:**

- [Scala 3 Reference](https://docs.scala-lang.org/scala3/reference/new-types/type-lambdas.html)
- [Scala 3 Reference, Details](https://docs.scala-lang.org/scala3/reference/new-types/type-lambdas-spec.html)
- [Type Lambdas, Polymorphic Function Types, and Dependent Function Types](https://medium.com/scala-3/scala-3-type-lambdas-polymorphic-function-types-and-dependent-function-types-2a6eabef896d?source=rss----de7527e0301e---4)
